package core.matrix;

import core.iterfaces.Matrix;
import core.iterfaces.Vec;
import core.vec.SparseVec;
import exception.NotSupportException;

/**
 * 对角矩阵，使用band[min(m,n)]矩阵存储
 *
 */
public class DiagMatrix implements Matrix {
    private Integer m;
    private Integer n;
    private Double[] band;
    public DiagMatrix(Integer m, Integer n){
        this.m = m;
        this.n = n;
        band = new Double[Math.min(m,n)];
    }

    public DiagMatrix(Integer m, Integer n, Double[] data){
        this.m = m;
        this.n = n;
        band = new Double[Math.min(m,n)];
        for (int i = 0; i < band.length; i++) {
            band[i]=data[i];
        }
    }
    @Override
    public Matrix zero() {
        return new DiagMatrix(this.m,this.n);
    }

    @Override
    public Matrix zero(int rowLen, int colLen) {
        return new DiagMatrix(rowLen,colLen);
    }

    @Override
    public double get(int i, int j) {
        if(i<0||i>(m-1)){
            throw new IndexOutOfBoundsException("传入的参数i:"+i+" 不符合矩阵行数范围");
        }
        if(j<0||j>(n-1)){
            throw new IndexOutOfBoundsException("传入的参数j:"+j+" 不符合矩阵列数范围");
        }
        if(i==j){
            return band[i];
        }
        return 0;
    }

    @Override
    public void set(int i, int j, double value) {
        if(i<0||i>(m-1)){
            throw new IndexOutOfBoundsException("传入的参数i:"+i+" 不符合矩阵行数范围");
        }
        if(j<0||j>(n-1)){
            throw new IndexOutOfBoundsException("传入的参数j:"+j+" 不符合矩阵列数范围");
        }
        if(i==j){
            band[i]=value;
        }
    }

    @Override
    public Vec getRow(int i) throws NotSupportException {
        if(i<0||i>(m-1)){
            throw new IndexOutOfBoundsException("传入的参数i:"+i+" 不符合矩阵行数范围");
        }
        Vec result = new SparseVec(m);
        if(i<Math.min(m,n)){
            result.set(i,get(i,i));
        }
        return result;
    }

    @Override
    public Vec getCol(int j) {
        if(j<0||j>(n-1)){
            throw new IndexOutOfBoundsException("传入的参数j:"+j+" 不符合矩阵列数范围");
        }
        Vec result = new SparseVec(m);
        if(j<Math.min(m,n)){
            result.set(j,get(j,j));
        }
        return result;
    }

    @Override
    public Vec getSubRow(int i, int begin, int end) throws NotSupportException {
        if(i<0||i>(m-1)){
            throw new IndexOutOfBoundsException("传入的参数i:"+i+" 不符合矩阵行数范围");
        }
        if(begin<0||begin>n-1){
            throw new IndexOutOfBoundsException("传入的参数begin:"+begin+" 不符合矩阵列数范围");
        }
        if(end<0||end>n){
            throw new IndexOutOfBoundsException("传入的参数end:"+end+" 不符合矩阵列数范围");
        }
        Vec result = new SparseVec(end-begin);
        if(i<Math.min(m,n)&&begin<=i&&i<end){
            result.set(i-begin,get(i,i));
        }

        return result;
    }

    @Override
    public Vec getSubCol(int j, int begin, int end) throws NotSupportException {
        if(j<0||j>(n-1)){
            throw new IndexOutOfBoundsException("传入的参数j:"+j+" 不符合矩阵列数范围");
        }
        if(begin<0||begin>m-1){
            throw new IndexOutOfBoundsException("传入的参数begin:"+begin+" 不符合矩阵行数范围");
        }
        if(end<0||begin>m){
            throw new IndexOutOfBoundsException("传入的参数end:"+end+" 不符合矩阵行数范围");
        }
        Vec result = new SparseVec(end-begin);
        if(j<Math.min(m,n)&&begin<=j&&j<end){
            result.set(j-begin,get(j,j));
        }
        return result;
    }

    @Override
    public int getRowLen() {
        return m;
    }

    @Override
    public int getColLen() {
        return n;
    }

    @Override
    public boolean isDense() {
        return false;
    }

    @Override
    public boolean isPositiveDefinite() {
        for (int i = 0; i < band.length; i++) {
            if(band[i]<0){
                return false;
            }
        }
        return true;
    }

    @Override
    public double norm2() {
        return 0;
    }

    @Override
    public Matrix toSparse() throws NotSupportException {
        Matrix result = new SparseMatrix(m,n);
        for (int i=0;i<Math.min(m,n);i++){
            result.set(i,i,get(i,i));
        }
        return result;
    }

    @Override
    public Matrix toDense() throws NotSupportException {
        Matrix result = new DenseMatrix(m,n);
        for (int i=0;i<Math.min(m,n);i++){
            result.set(i,i,get(i,i));
        }
        return result;
    }

    @Override
    public Vec getKDiag(int k) throws NotSupportException {
        int len = diagLength(k);
        Vec result = new SparseVec(len);
        if(0==k){
            for (int i = 0; i < len; i++) {
                result.set(i,band[i]);
            }
        }
        return result;
    }

    @Override
    public Matrix sub(int rowBegin, int rowEnd, int colBegin, int colEnd) throws NotSupportException {
        return null;
    }

    @Override
    public Matrix transform() {
        DiagMatrix diagMatrix = new DiagMatrix(getRowLen(),getColLen(),band);
        return diagMatrix;
    }

    @Override
    public Matrix muti(double a, boolean isCovered) {
        if(isCovered){
            for (int i = 0; i < band.length; i++) {
                band[i] = band[i]*a;
            }
            return this;
        }
        else {
            DiagMatrix diagMatrix = new DiagMatrix(getRowLen(),getColLen(),band);
            return diagMatrix.muti(a,true);
        }
    }

    @Override
    public Vec muti(Vec v) throws NotSupportException {
        if(getColLen()!=v.len()){
            throw new NotSupportException("矩阵宽度和向量长度不兼容");
        }
        Vec result = new SparseVec(getRowLen());
        for (int i = 0; i < band.length; i++) {
            result.set(i,v.get(i)*band[i]);
        }
        return result;
    }

    @Override
    public Matrix muti(Matrix other) throws NotSupportException {
        if(getColLen()!=other.getRowLen()){
            throw new NotSupportException("两个矩阵宽度和长度不兼容");
        }
        Matrix result = other.zero(getRowLen(), other.getColLen());
        /**
         * D*A 表示对A的行加权
         */
        for (int i = 0; i < band.length; i++) {
            for (int j = 0; j < result.getColLen(); j++) {
                    result.set(i, j, band[i] *other.get(i,j));
            }
        }
        return result;
    }




    @Override
    public boolean isLowerTri() {
        return true;
    }

    @Override
    public boolean isUpperTri() {
        return true;
    }

    @Override
    public boolean isHessenberg() {
        return true;
    }

    @Override
    public boolean isSymmetric() {
        return getColLen()==getRowLen();
    }

    @Override
    public boolean isTriDiag() {
        return true;
    }

    @Override
    public void exchangeRow(int i, int j) {
        throw new RuntimeException("对角矩阵不支持此操作");
    }

    @Override
    public void exchangeCol(int i, int j) {
        throw new RuntimeException("对角矩阵不支持此操作");
    }

    @Override
    public double fnorm() {
        double result = 0.0;
        for (int i = 0; i < band.length; i++) {
            result+=Math.pow(band[i],2);
        }
        return result;
    }

    @Override
    public double off() {
        double result = Math.abs(band[0]);
        for (int i = 1; i < band.length; i++) {
            if (result<Math.abs(band[i])){
                result = Math.abs(band[i]);
            }
        }
        return result;
    }

    @Override
    public double norm1() {
        return off();
    }

    @Override
    public Matrix abs(boolean isCovered) {
        if(isCovered){
            for (int i = 0; i < band.length; i++) {
                 band[i]=Math.abs(band[i]);
            }
            return this;
        }
        else{
            Matrix result = zero();
            for (int i = 0; i < band.length; i++) {
                result.set(i,i,Math.abs(band[i]));
            }
            return result;
        }
    }
}
